"""
增强API测试基类
提供更丰富的API测试功能和便捷方法
"""

import json
from typing import Dict, Any, Optional, List
from unittest.mock import Mock, patch

from fastapi.testclient import TestClient

from app.main import app
from tests.api.base_api_test import BaseAPITest
from tests.factories.test_data_factory import (
    create_user_create_data,
    create_role_create_data,
    create_permission_create_data
)
from tests.utils import (
    create_mock_user,
    create_mock_role,
    create_mock_permission,
    assert_response_status,
    assert_response_data,
    assert_validation_error,
    assert_authentication_error,
    assert_authorization_error
)


class EnhancedAPITest(BaseAPITest):
    """增强API测试基类"""
    
    def setup_method(self):
        """每个测试方法前的设置"""
        super().setup_method()
        
        # 初始化测试数据工厂
        self.test_data_factory = None  # 在需要时初始化
    
    def create_auth_headers(self, token: Optional[str] = None) -> Dict[str, str]:
        """创建认证头"""
        if token is None:
            token = self.access_token
        return {"Authorization": f"Bearer {token}"}
    
    def create_admin_user(self) -> Mock:
        """创建管理员用户"""
        admin_user = create_mock_user(
            user_id=1,
            username="admin",
            email="admin@example.com",
            is_superuser=True
        )
        return admin_user
    
    def create_regular_user(self) -> Mock:
        """创建普通用户"""
        regular_user = create_mock_user(
            user_id=2,
            username="regular_user",
            email="user@example.com",
            is_superuser=False
        )
        return regular_user
    
    # 通用HTTP方法测试
    
    def test_get_request_with_query_params(self, endpoint: str, params: Dict[str, Any],
                                         expected_status: int = 200,
                                         headers: Optional[Dict[str, str]] = None) -> Any:
        """测试带查询参数的GET请求"""
        if headers is None:
            headers = self.get_auth_headers()
            
        response = self.client.get(endpoint, params=params, headers=headers)
        assert_response_status(response, expected_status)
        return response
    
    def test_post_request_with_files(self, endpoint: str, files: Dict[str, Any],
                                   data: Optional[Dict[str, Any]] = None,
                                   expected_status: int = 200,
                                   headers: Optional[Dict[str, str]] = None) -> Any:
        """测试带文件的POST请求"""
        if headers is None:
            headers = self.get_auth_headers()
            
        response = self.client.post(endpoint, files=files, data=data, headers=headers)
        assert_response_status(response, expected_status)
        return response
    
    def test_put_request_with_files(self, endpoint: str, files: Dict[str, Any],
                                  data: Optional[Dict[str, Any]] = None,
                                  expected_status: int = 200,
                                  headers: Optional[Dict[str, str]] = None) -> Any:
        """测试带文件的PUT请求"""
        if headers is None:
            headers = self.get_auth_headers()
            
        response = self.client.put(endpoint, files=files, data=data, headers=headers)
        assert_response_status(response, expected_status)
        return response
    
    # 认证相关测试方法
    
    def test_login_success(self, email: str = "test@example.com",
                          password: str = "StrongPassword123!") -> Dict[str, Any]:
        """测试登录成功"""
        login_data = {
            "email": email,
            "password": password
        }
        
        response = self.client.post("/api/v1/auth/login", json=login_data)
        assert_response_status(response, 200)
        
        data = response.json()
        assert "access_token" in data
        assert "refresh_token" in data
        assert data["token_type"] == "bearer"
        
        return data
    
    def test_login_failure(self, email: str = "test@example.com",
                          password: str = "wrong_password") -> Dict[str, Any]:
        """测试登录失败"""
        login_data = {
            "email": email,
            "password": password
        }
        
        response = self.client.post("/api/v1/auth/login", json=login_data)
        assert_response_status(response, 401)
        
        data = response.json()
        assert "detail" in data
        assert "邮箱或密码错误" in data["detail"]
        
        return data
    
    def test_register_success(self, register_data: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
        """测试注册成功"""
        if register_data is None:
            register_data = create_user_create_data().dict()
        
        response = self.client.post("/api/v1/auth/register", json=register_data)
        assert_response_status(response, 200)
        
        data = response.json()
        assert "id" in data
        assert data["username"] == register_data["username"]
        assert data["email"] == register_data["email"]
        
        return data
    
    def test_register_failure(self, register_data: Dict[str, Any]) -> Dict[str, Any]:
        """测试注册失败"""
        response = self.client.post("/api/v1/auth/register", json=register_data)
        # 状态码取决于具体的验证错误
        assert response.status_code in [400, 422]
        
        data = response.json()
        assert "detail" in data
        
        return data
    
    # 用户管理API测试方法
    
    def test_create_user_success(self, user_data: Optional[Dict[str, Any]] = None,
                                expected_status: int = 200) -> Dict[str, Any]:
        """测试创建用户成功"""
        if user_data is None:
            user_data = create_user_create_data().dict()
        
        response = self.test_post_request(
            "/api/v1/users/",
            user_data,
            expected_status=expected_status
        )
        
        if expected_status == 200:
            data = response.json()
            assert "id" in data
            assert data["username"] == user_data["username"]
            assert data["email"] == user_data["email"]
            return data
        else:
            return response.json()
    
    def test_get_users_list(self, params: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
        """测试获取用户列表"""
        if params is None:
            params = {}
            
        response = self.test_get_request_with_query_params(
            "/api/v1/users/",
            params=params,
            expected_status=200
        )
        
        data = response.json()
        assert "items" in data
        assert "total" in data
        assert "page" in data
        assert "size" in data
        
        return data
    
    def test_get_user_by_id(self, user_id: int = 1) -> Dict[str, Any]:
        """测试根据ID获取用户"""
        response = self.test_get_request(
            f"/api/v1/users/{user_id}",
            expected_status=200
        )
        
        data = response.json()
        assert "id" in data
        assert data["id"] == user_id
        
        return data
    
    def test_update_user_success(self, user_id: int = 1,
                                update_data: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
        """测试更新用户成功"""
        if update_data is None:
            update_data = {
                "full_name": "Updated Name",
                "phone": "9876543210"
            }
        
        response = self.test_put_request(
            f"/api/v1/users/{user_id}",
            update_data,
            expected_status=200
        )
        
        data = response.json()
        assert data["id"] == user_id
        for key, value in update_data.items():
            assert data[key] == value
            
        return data
    
    def test_delete_user_success(self, user_id: int = 1) -> Dict[str, Any]:
        """测试删除用户成功"""
        response = self.test_delete_request(
            f"/api/v1/users/{user_id}",
            expected_status=200
        )
        
        data = response.json()
        assert "message" in data
        assert "successfully" in data["message"].lower()
        
        return data
    
    # 角色管理API测试方法
    
    def test_create_role_success(self, role_data: Optional[Dict[str, Any]] = None,
                                expected_status: int = 200) -> Dict[str, Any]:
        """测试创建角色成功"""
        if role_data is None:
            role_data = create_role_create_data().dict()
        
        response = self.test_post_request(
            "/api/v1/roles/",
            role_data,
            expected_status=expected_status
        )
        
        if expected_status == 200:
            data = response.json()
            assert "id" in data
            assert data["name"] == role_data["name"]
            return data
        else:
            return response.json()
    
    def test_get_roles_list(self, params: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
        """测试获取角色列表"""
        if params is None:
            params = {}
            
        response = self.test_get_request_with_query_params(
            "/api/v1/roles/",
            params=params,
            expected_status=200
        )
        
        data = response.json()
        assert "items" in data
        assert "total" in data
        
        return data
    
    # 权限管理API测试方法
    
    def test_create_permission_success(self, permission_data: Optional[Dict[str, Any]] = None,
                                     expected_status: int = 200) -> Dict[str, Any]:
        """测试创建权限成功"""
        if permission_data is None:
            permission_data = create_permission_create_data().dict()
        
        response = self.test_post_request(
            "/api/v1/permissions/",
            permission_data,
            expected_status=expected_status
        )
        
        if expected_status == 200:
            data = response.json()
            assert "id" in data
            assert data["name"] == permission_data["name"]
            return data
        else:
            return response.json()
    
    def test_get_permissions_list(self, params: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
        """测试获取权限列表"""
        if params is None:
            params = {}
            
        response = self.test_get_request_with_query_params(
            "/api/v1/permissions/",
            params=params,
            expected_status=200
        )
        
        data = response.json()
        assert "items" in data
        assert "total" in data
        
        return data
    
    # 断言方法增强
    
    def assert_pagination_response(self, response, expected_page: int = 1, expected_size: int = 10):
        """断言分页响应"""
        data = response.json()
        assert "items" in data
        assert "total" in data
        assert "page" in data
        assert "size" in data
        assert data["page"] == expected_page
        assert data["size"] == expected_size
    
    def assert_list_response(self, response, min_count: int = 0):
        """断言列表响应"""
        data = response.json()
        assert "items" in data
        assert isinstance(data["items"], list)
        assert len(data["items"]) >= min_count
    
    def assert_search_response(self, response, search_keyword: str):
        """断言搜索响应"""
        data = response.json()
        assert "items" in data
        # 简单检查至少有一个项目（实际搜索验证应在具体测试中实现）
        assert isinstance(data["items"], list)
    
    def assert_sort_response(self, response, sort_field: str, ascending: bool = True):
        """断言排序响应"""
        data = response.json()
        assert "items" in data
        items = data["items"]
        if len(items) > 1:
            # 简单检查排序（实际排序验证应在具体测试中实现）
            pass
    
    # 性能和安全测试方法
    
    def test_rate_limiting(self, endpoint: str, method: str = "GET",
                          request_count: int = 10) -> List[Any]:
        """测试速率限制"""
        responses = []
        
        for i in range(request_count):
            if method.upper() == "GET":
                response = self.client.get(endpoint, headers=self.get_auth_headers())
            elif method.upper() == "POST":
                response = self.client.post(endpoint, headers=self.get_auth_headers())
            elif method.upper() == "PUT":
                response = self.client.put(endpoint, headers=self.get_auth_headers())
            elif method.upper() == "DELETE":
                response = self.client.delete(endpoint, headers=self.get_auth_headers())
            else:
                raise ValueError(f"Unsupported method: {method}")
                
            responses.append(response)
            
        return responses
    
    def test_input_validation(self, endpoint: str, invalid_data: Dict[str, Any],
                             method: str = "POST") -> Any:
        """测试输入验证"""
        if method.upper() == "POST":
            response = self.client.post(endpoint, json=invalid_data, headers=self.get_auth_headers())
        elif method.upper() == "PUT":
            response = self.client.put(endpoint, json=invalid_data, headers=self.get_auth_headers())
        else:
            raise ValueError(f"Unsupported method for validation test: {method}")
            
        assert_validation_error(response)
        return response
    
    def test_authentication_required(self, endpoint: str, method: str = "GET") -> Any:
        """测试需要认证"""
        # 不带认证头的请求
        if method.upper() == "GET":
            response = self.client.get(endpoint)
        elif method.upper() == "POST":
            response = self.client.post(endpoint)
        elif method.upper() == "PUT":
            response = self.client.put(endpoint)
        elif method.upper() == "DELETE":
            response = self.client.delete(endpoint)
        else:
            raise ValueError(f"Unsupported method: {method}")
            
        assert_authentication_error(response)
        return response
    
    def test_authorization_required(self, endpoint: str, method: str = "GET") -> Any:
        """测试需要授权"""
        # 使用普通用户权限测试需要管理员权限的端点
        regular_user_headers = self.create_auth_headers("regular_user_token")
        
        if method.upper() == "GET":
            response = self.client.get(endpoint, headers=regular_user_headers)
        elif method.upper() == "POST":
            response = self.client.post(endpoint, headers=regular_user_headers)
        elif method.upper() == "PUT":
            response = self.client.put(endpoint, headers=regular_user_headers)
        elif method.upper() == "DELETE":
            response = self.client.delete(endpoint, headers=regular_user_headers)
        else:
            raise ValueError(f"Unsupported method: {method}")
            
        assert_authorization_error(response)
        return response